﻿

#region File Description

#endregion


#region Using Statements

// System References
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using System.IO;

// XNA References
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

// Freeform References
using Freeform.Framework;
using Freeform.Framework.Graphics;
using Freeform.Framework.Utility;
using Freeform.Framework.Input;
using Freeform.Framework.Menu;

// Internal References

#endregion


namespace CardGame.Adventure.Editor
{
    public class EditorTileClass : Entity
    {

        #region Members

        public Point AxisDifference { get; set; }
        public Int32 TileWidth { get; set; }
        public Int32 TileHeight { get; set; }
        public Int32 NumberOfTextures { get; set; }
        public string ArtFileName { get; set; }
        public Texture2D ArtSource { get; set; }
        public Int32 MapWidth { get; set; }
        public Int32 MapHeight { get; set; }
        public Vector4[][] MapGrid { get; set; }
        public Int32 DrawTileWidth {get; private set;}
        public Int32 DrawTileHeight { get; private set; }


        private List<Color> HeightColor = new List<Color>();
        private Single MapAngle;
        private Color LeftWallColor;
        private Color RightWallColor;
        private Single TileDepth;
        private SpriteFont Debug;
        private Point SelectedTile;
        private Texture2D Art;
        private Texture2D IsoArt;
        private Texture2D ArtRamp;
        private Rectangle GUIArea;

        public bool IntiateSaveProcedure = false;
        public bool IntiateLoadProcedure = false;
        public bool IsVisible = true;

        public string FileName = "Content/Default5";
        // DOODADS NEED TO BE IMPLEMENTED
        // THEY WILL BE SORTED FOR CORRECT DEPTH SORTING
        // REGULAR TILES WILL NOT BE.
        // MapGrid is now a jagged array to ease serialization. Multi-Dimensionals cannot be serialized.
        #endregion


        #region Initialisation

        public EditorTileClass(World W, int MapH, int MapW)
           : base(W)
        {
            Random r = new Random();
            TileWidth = 64;
            TileHeight = 64;
            DrawTileWidth = 32;
            DrawTileHeight = 32;
            MapWidth = MapW;
            MapHeight = MapH;
            MapGrid = new Vector4[MapHeight][];
            for (int i = 0; i < MapHeight; i++)
                MapGrid[i] = new Vector4[MapWidth];
            for (int i = 0; i < MapHeight; i++)
                for (int a = 0; a < MapWidth; a++)
                    MapGrid[i][a] = new Vector4(r.Next(2), 1, 1, 1);

            HeightColor.Add(Color.AliceBlue);
            HeightColor.Add(Color.LightGreen);
            ArtFileName = "tempArtthree";
            ArtSource = Game.Content.Load<Texture2D>("Texture/Adventure/Art/" + ArtFileName);
            Art = Game.Content.Load<Texture2D>("Texture/Adventure/Art/ttblock");
            ArtRamp = Game.Content.Load<Texture2D>("Texture/Adventure/Art/tempArtRamp");
            IsoArt = Game.Content.Load<Texture2D>("Texture/Adventure/Art/ttwall");
            MapAngle = 0f;
            TileDepth = 0.5f;
            Debug = Game.Content.Load<SpriteFont>("Font/Basic");

            LeftWallColor = new Color(150, 100, 150);
            RightWallColor = new Color(255, 50, 50);
            SelectedTile = Point.Zero;
            GUIArea = new Rectangle(80, 0, 20, 100);
        }

        #endregion


        #region Draw

        /// <summary>
        /// Draws the entity onto the viewport.
        /// </summary>
        /// <param name="spatial">The spatial properties of the actor in world coordinates.</param>
        /// <param name="viewport">The viewport onto which the entity is being rendered.</param>
        /// <param name="time">Provides a snapshot of timing values.</param>

        protected override void DoDraw(GameTime Time, Viewport2D Viewport)
        {
            // Check early breaks.
            if (Viewport.SpriteBatch == null) return;
            if (this == null) return;
            if (!IsVisible) return;

            // Calculate drawing data.
            Vector2 Draw_Position = Viewport.Camera.TransformPosition(SpatialProperties.Position);
            Vector2 Draw_Size = new Vector2(DrawTileWidth, DrawTileHeight);
            Rectangle Draw_Source = new Rectangle(0, 0, 64, 64);

            SelectedTile = new Point((int)((Viewport.RenderTarget.Width / DrawTileWidth) * (SpatialProperties.Position.X +
               Viewport.MouseLocation_View.X)),
               (int)((Viewport.RenderTarget.Height / DrawTileHeight) * (SpatialProperties.Position.Y +
               Viewport.MouseLocation_View.Y)));
            Point DrawSquare = SelectedTile;
            Rectangle Draw_Mouse = new Rectangle(
                (int)(DrawSquare.X * DrawTileWidth), (int)(DrawSquare.Y * DrawTileHeight),
                (int)Draw_Size.X, (int)Draw_Size.Y);

            SelectedTile = new Point(SelectedTile.X + AxisDifference.X, SelectedTile.Y + AxisDifference.Y);

            Vector4 TileInformation = Vector4.Zero;
            if (CheckSelectedBounds())
                TileInformation = MapGrid[SelectedTile.X][SelectedTile.Y];

            if (Viewport.MouseLocation_View.X * 100 > GUIArea.Left)
            {
                TileInformation = new Vector4(-1, -1, -1, -1);
                SelectedTile = new Point(-1, -1);
            }
            // Begin drawing.
            TileDepth = 0.5f;
            Single WallDepth = 0.5f;

            for (int CurrentHeightLayer = 0; CurrentHeightLayer <= 9; CurrentHeightLayer++)
            {
                WallDepth = TileDepth;
                for (int i = 0; i < MapHeight; i++)
                {
                    for (int a = 0; a < MapWidth; a++)
                    {
                        float Height = MapGrid[i][a].Y;
                        Color Draw_Color = HeightColor[(int)MapGrid[i][a].X];

                        TileDepth += .00001f;
                        WallDepth += 0.000001f;

                        if (Height == CurrentHeightLayer || Height == CurrentHeightLayer + 0.5f)
                        {
                            Draw_Size = new Vector2(DrawTileWidth, DrawTileHeight);
                            Draw_Source = new Rectangle(0, 0, 64, 64);
                            Draw_Color = new Color(Draw_Color.R - (30 * CurrentHeightLayer), Draw_Color.G - (30 * CurrentHeightLayer), Draw_Color.B - (30 * CurrentHeightLayer));
                            Rectangle Draw_DestinationHeight = new Rectangle(
                                (int)Draw_Position.X + ((i * DrawTileWidth)), (int)Draw_Position.Y + ((a * DrawTileHeight)),
                                (int)Draw_Size.X, (int)Draw_Size.Y);
                            Viewport.SpriteBatch.Draw(Art, Draw_DestinationHeight, Draw_Source, Draw_Color, MapAngle, Vector2.Zero, SpriteEffects.None, TileDepth);

                            if (Height > 0)
                            {
                                Viewport.SpriteBatch.DrawString(Debug, MapGrid[i][a].Y.ToString(),
                                    new Vector2(Draw_DestinationHeight.X, Draw_DestinationHeight.Y), Color.LightBlue, 0f, Vector2
                                    .Zero, 0.5f, SpriteEffects.None, 0.69f);
                            }
                        }
                    }
                }
            }

            if (TileInformation.X != -1)
            {
                Viewport.SpriteBatch.Draw(Art, Draw_Mouse, Draw_Source, Color.CadetBlue, MapAngle, Vector2.Zero, SpriteEffects.FlipHorizontally, 0.8f);
                Viewport.SpriteBatch.DrawString(Debug, ( "[" + SelectedTile.X.ToString() +"," + SelectedTile.Y.ToString() + "]" + "{T:" + TileInformation.X.ToString()
                    + " H:" + TileInformation.Y.ToString())+ " W:" + TileInformation.W.ToString() + " W:" + TileInformation.Z.ToString() + "}",
                    new Vector2(Draw_Mouse.X, Draw_Mouse.Y - TileHeight), Color.Fuchsia, 0f, Vector2
                    .Zero, 1f, SpriteEffects.None, 1f);
            }
        }

        #endregion


        #region Update
        protected override void DoUpdate(GameTime Time)
        {

            if (IntiateSaveProcedure)
            {
                SaveMap("Content/" + FileName + ".xml");
                IntiateSaveProcedure = false;
            }

            if (IntiateLoadProcedure)
            {
                LoadMap("Content/" + FileName + ".xml");
                SetUpArtAssets();
                IntiateLoadProcedure = false;
            }

            base.DoUpdate(Time);
        }
        #endregion


        #region Utility

        public void SaveMap(string filename)
        {
            EditorProtoClass Proto = ConversionClass.ToProtoClass(this);
            XmlSerializer Serializer = new XmlSerializer(typeof(EditorProtoClass));
            TextWriter txtWriter = new StreamWriter(filename);

            Serializer.Serialize(txtWriter, Proto);
            txtWriter.Close();
        }

        public EditorTileClass LoadMap(string filename)
        {
            EditorTileClass Existing = this;
            EditorProtoClass Proto = new EditorProtoClass();
            XmlSerializer xml = new XmlSerializer(typeof(EditorProtoClass));
            Stream xmlReader = new FileStream(filename, FileMode.Open);

            Proto = (EditorProtoClass)xml.Deserialize(xmlReader);

            Existing = ConversionClass.ToTileClass(Proto, Existing);

            xmlReader.Close();

            //TODO: Load textures and un-serializable content.

            return Existing;
        }

        /// <summary>
        /// Used to do modify 'mouse poisiton' of the map grid.
        /// </summary>
        /// <param name="index">'X' 'Y' 'W' or 'Z' for TexIndex, Height, WallTex1 and WallTex2 respectively.</param>
        /// <param name="Modification">float number added in the vector4.</param>
        public void ModifyCell(char index, float Modification)
        {
            CheckSelectedBounds();

            if (index == 'X')
                MapGrid[SelectedTile.X][SelectedTile.Y].X += Modification;
            if (index == 'Y')
                MapGrid[SelectedTile.X][SelectedTile.Y].Y += Modification;
            if (index == 'W')
                MapGrid[SelectedTile.X][SelectedTile.Y].W += Modification;
            if (index == 'Z')
                MapGrid[SelectedTile.X][SelectedTile.Y].Z += Modification;
        }

        /// <summary>
        /// Used to explicitly set 'mouse poisiton' of the map grid to a value.
        /// </summary>
        /// <param name="index">'X' 'Y' 'W' or 'Z' for TexIndex, Height, WallTex1 and WallTex2 respectively.</param>
        /// <param name="Modification">float number stored in the vector4.</param>
        public void SetCell(char index, float Modification)
        {
            CheckSelectedBounds();

            if (index == 'X')
                MapGrid[SelectedTile.X][SelectedTile.Y].X = Modification;
            if (index == 'Y')
                MapGrid[SelectedTile.X][SelectedTile.Y].Y = Modification;
            if (index == 'W')
                MapGrid[SelectedTile.X][SelectedTile.Y].W = Modification;
            if (index == 'Z')
                MapGrid[SelectedTile.X][SelectedTile.Y].Z = Modification;
        }

        private Boolean CheckSelectedBounds()
        {
            if (SelectedTile.X >= MapWidth)
                SelectedTile.X = MapWidth - 1;
            if (SelectedTile.Y >= MapHeight)
                SelectedTile.Y = MapHeight - 1;
            if (SelectedTile.X < 0)
                SelectedTile.X = 0;
            if (SelectedTile.Y < 0)
                SelectedTile.Y = 0;
            if (SelectedTile.X != -1)
                return true;
            else
                return false;
        }

        public void SetUpArtAssets()
        {
            if (ArtFileName == "" || ArtFileName == null)
                ArtFileName = "tempArtthree";

            DirectoryInfo Dir = new DirectoryInfo(Game.Content.RootDirectory + "/Texture/Adventure/Art/");
            if (!Dir.Exists)
                throw new DirectoryNotFoundException();

            FileInfo[] Files = Dir.GetFiles("*.*");
            foreach (FileInfo F in Files)
            {
                string literal = Path.GetFileNameWithoutExtension(F.Name);
                if (literal == ArtFileName)
                {
                    if (F.Extension == ".xnb")
                    {
                        ArtSource = Game.Content.Load<Texture2D>("Texture/Adventure/Art/" + ArtFileName);
                        break;
                    }
                    else if (F.Extension == ".png")
                    {
                        Stream stream = File.OpenRead("Texture/Adventure/Art/" + ArtFileName + ".png");
                        ArtSource = Texture2D.FromStream(Game.GraphicsDevice, stream);
                        stream.Close();
                        break;
                    }
                }
            }

            if (ArtSource != null)
            {
                int numberOfColors = ArtSource.Width / 64;
                NumberOfTextures = numberOfColors;
                HeightColor.Clear();
                for (int i = 0; i < numberOfColors; i++)
                {
                    Color[] tempColor = new Color[1];
                    Rectangle sourceRect = new Rectangle((64 * i), 48, 1, 1);
                    ArtSource.GetData<Color>(0, sourceRect, tempColor, 0, 1);
                    HeightColor.Add(tempColor[0]);
                }
            }
        }
        #endregion

    }
}
